import top.starp.util.StringUtil;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;

/**
 * class:
 * --LL1:
 * 实现LL(1)分析,构造分析预测程序（FIRST集-->FOLLOW集-->分析预测表-->stack预测分析）
 * --Gui:
 * 读取输入串，桌面程序展示分析预测步骤
 */

public class LL1 {
//    是他找到的第一个终结符 no ter to fir set T -> [(, i]  比如 T "T->FS" 他是可以找S 的吗，S 的话 会去"S->ε" 但是他没有
//    说明他不会找S ，只会找 F ，F 确实是 F -> [(, i]  ，所以 T 和F 一样的 T -> [(, i]
//    E -> [#, )]
//   follow 集合  F -> [#, ), *, +, -, /]
//    F 后面 S ， S *FS ， F*F*F*....S
//    "T->FS", "S->*FS|/FS" F/FS  F/F/F....S
//{"E->TG" E->FSG
//    就是把他转化开来 成为有个终止符的样子吧 就和之前手动的差不多的意思
//    E比较复杂 先不管
//    G->+TG|-TG G->+FSG +FS+FS...G
//    static String[] grammarStr = {"E->TG", "G->+TG|-TG", "G->ε", "T->FS", "S->*FS|/FS", "S->ε", "F->(E)", "F->i"};//相关文法
//static Character start = 'E';


//    static String[] grammarStr = {"S->A", "A->B|AiB", "B->C|B+C", "C->)A*|(",};//相关文法
//    static Character start = 'S';
//    栈溢出
//    但是中间应该看到fir 有 （  ） 两种都有吧
//    找不到S 怎么没了

//    static String[] grammarStr = {"S -> + S S", "S -> * S S", "S -> a ", };//相关文法
//    static String[] grammarStr = {"Stm -> Stm ; Stm", "S -> * S S", "S -> a ", };//相关文法
    static String[] grammarStr = {"S -> {S ; S}", "S -> i = E", "S -> p ( E )",  "E -> i","E -> 1","E -> E B E",
            "L -> E , L","L -> E","B -> +","B -> -","B -> *","B -> /",};//相关文法
//    static String inStr = "i+i*i#";//输入串
//    static String inStr = "{i=1+1;i=(p(i,i-1),1*i);p(i)#}";//输入串
    static String inStr = "{i=1+1;i=(p(i,i-1),1*i);};{p(i)}#";//输入串
//    static String inStr = "i=1+1 i=(p(i,i-1),1*i) p(i)#";//输入串
//    static String inStr = "i=1+1 i=(p(i,i-1),1*i) p(i)#";//输入串
//    貌似都是一个char
    static Character start = 'S';

    static HashMap<Character, ArrayList<String>> production = new HashMap<>();//产生式
    static HashMap<Character, HashSet<Character>> FirstSet = new HashMap<>();//构造FIRST集合
    static HashMap<String, HashSet<Character>> FirstSetX = new HashMap<>();//生成任何符号串的first
    static HashMap<Character, HashSet<Character>> FollowSet = new HashMap<>();//构造FOLLOW集合
    static String[][] table;//预测分析表
//    Non Terminator
//    NonTerminator
//    static HashSet<Character> VnSet = new HashSet<>();//非终结符Vn集合
    static HashSet<Character> NonTerminatorSet = new HashSet<>();//非终结符Vn集合
//    static HashSet<Character> VtSet = new HashSet<>();//终结符Vt集合
    static HashSet<Character> TerSet = new HashSet<>();//终结符Vt集合
    static Stack<Character> stack = new Stack<>();  //符号栈
//    static String inStr = "i+i*i#";//输入串
//    static Character start = 'E';

    static int index = 0;//输入字符指针
    static String action = "";
    static ArrayList<Vector> stepList = new ArrayList<>();//与LL（1）无关，可不关心，为GUI记录了stack每一步的变化
//    public static void main(String[] args) {
//        dividechar();
//        First();
//        for (Character c : VnSet) {
//            ArrayList<String> l = production.get(c);
//            for (String s : l)
//                getFirstX(s);
//        }
//        Follow();
//        creatTable();
//        ouput();
//        processLL1();
//
//    }

    /**
     * 生成产生式Map(production)，划分终结符（vt）与非终结符（vn）
     */
    static void divideChar() {
        //生成产生式Map(production)
        for (int i = 0; i < grammarStr.length; i++) {
//            grammarStr[i]=     grammarStr[i].trim();
            grammarStr[i]=  StringUtil.removeBlank(grammarStr[i]);
//            grammarStr[i]=     grammarStr[i].trim();
        }
        System.out.println("grammarStr 去掉空格之后");
        System.out.println(Arrays.toString(grammarStr));
        for (String str : grammarStr
        ) {
            //将“|”相连的产生式分开
//            获取右边的
            String[] tokens = str.split("->")[1].split("\\|");
            System.out.println("==========");
            System.out.println("将“|”相连的产生式分开 生成 右边的那些可能：");
            System.out.println(Arrays.toString(tokens));
            //非终结符
//            char Vch = str.charAt(0);
            char nonTerCh = str.charAt(0);
            System.out.println("Vch 非终结符");
            System.out.println(nonTerCh);
//            也就是左边的那个开始 的 E->TG 里面的 E  因为非终结符 这里设置的都是一个大写字母
            ArrayList<String> listProductions = production.containsKey(nonTerCh) ? production.get(nonTerCh) : new ArrayList<String>();
            System.out.println("非终结符 之前有哪些产生式 ");
            System.out.println(listProductions);
//            和输入串有关 但是咋弄呢
            for (String token : tokens
            ) {
//                比如新加的 ε 被加入了
                listProductions.add(token);
            }
//            "G->+TG|-TG", "G->ε",
//           G之前可以 产生 G->+TG|-TG  他被加入了
            System.out.println("有新的产生式了 ");
            System.out.println(listProductions);
//            production.put(str.charAt(0), listProductions);
            production.put(nonTerCh, listProductions);
            NonTerminatorSet.add(nonTerCh);
//            非终结符 就是一开始左边的那些 一开始就定好了
//            假如一开始 非终结符有T 也只有右边的找到的T 可以是非终结符
//            其他的一律认为是终结符 也就是说 他生不出东西来了 就此打住
//            比如这里的 i 他就没办法 i -> 生出什么东西
        }
        //寻找终结符
        System.out.println("==========");
        System.out.println("寻找终结符");
        for (Character nonTermCh : NonTerminatorSet
        ) {
            for (String prodStr : production.get(nonTermCh)
            ) {
//                System.out.println("prodStr 产生的字符串");
//                System.out.println(prodStr);
//                System.out.println(String.format());
                System.out.println("========");
                System.out.println(String.format("%s -> %s", nonTermCh,prodStr));
//                \他是每种字符都可以生产吗 因为非终结符是大写的 一个字符 他是可以被别的替代的 可以产生东西的那个

                System.out.println("现在的非终结符集合是 ");
                System.out.println(NonTerminatorSet);
                System.out.println("找到产生的里面不是非终结符的 比如E 是非终结符 ，( 不是非终结符，话说不是非终结符的话 就是终结符吗。。不懂");
                for (Character prodCh : prodStr.toCharArray()
                ) {
                    if (!NonTerminatorSet.contains(prodCh)){
                        TerSet.add(prodCh);
//                        System.out.println("不是终结符的 "+prodCh);
                        System.out.println("不是非终结符的 "+prodCh);
                    }

                }
                System.out.println("终结符喜添新成员 现在是");
                System.out.println(TerSet);
            }

        }

    }

    /**
     * https://blog.csdn.net/qq_43046501/article/details/109043824
     * 生成非终结符的FIRST集的递归入口
     */
    static void First() {
        //遍历求每一个非终结符vn的first集
//        for (Character vn : NonTerminatorSet
        for (Character noTer : NonTerminatorSet
        ) {
            getfisrst(noTer);
        }
    }

    /**
     * 生成非终结符FIRST集的递归程序
     */
    static void getfisrst(Character noTer) {
//        F -> fir [(, i]
        ArrayList<String> ch_production = production.get(noTer);
        HashSet<Character> fir = FirstSet.containsKey(noTer) ? FirstSet.get(noTer) : new HashSet<>();
//        已有的基础上 增加 fir
        // 当ch为终结符
        if (TerSet.contains(noTer)) {
            System.out.println("$$$$$$$$$$$$$$$$$$$");
            System.out.println("终结符 结束");

            fir.add(noTer);
            FirstSet.put(noTer, fir);
            System.out.println(String.format("%s -> %s",noTer,fir ));
            return;
        }
        //ch为vn 非终结符
        for (String prodStr : ch_production
        ) {
//            他产生的所有 产生式
            int i = 0;
            System.out.println("==-=-=-=--=-=-=-=-");
//            System.out.println("prodStr 产生字符串" );
            System.out.println(String.format("%s -> %s",noTer,prodStr ));
//            System.out.println(prodStr);
            while (i < prodStr.length()) {
//                char tn = prodStr.charAt(i);
                char prodCh = prodStr.charAt(i);
//                的所有的字符  如果是noTer 就继续递归产生东西，他是不是noTer 是递归的入口会判断的
//                这里就不判断了
                //递归
//                继续产生东西
                getfisrst(prodCh);
//                HashSet<Character> tvSet = FirstSet.get(prodCh);
                HashSet<Character> allReadyFir = FirstSet.get(prodCh);
                // 将其first集加入左部
                System.out.println("将其first集加入左部");
//                System.out.println(tvSet);
//                System.out.println("% -> fir %s",prodCh+"",tvSet.toString());
                System.out.println(String.format("%c -> fir %s",prodCh,allReadyFir.toString()));
//                新加的fir
                for (Character tmp : allReadyFir) {
                    if (tmp != 'ε')
                        fir.add(tmp);
                }
                // 若包含空串 处理下一个符号
                if (allReadyFir.contains('ε'))
                    i++;
                    // 否则退出 处理下一个产生式
                else
                    break;
            }
            if (i == prodStr.length())
                fir.add('ε');
        }
        FirstSet.put(noTer, fir);
    }

    /**
     * 生成任何符号串的first
     */
    static void getFirstX(String s) {

        HashSet<Character> set = (FirstSetX.containsKey(s)) ? FirstSetX.get(s) : new HashSet<Character>();
        // 从左往右扫描该式
        int i = 0;
        while (i < s.length()) {
            char tn = s.charAt(i);
            if (!FirstSet.containsKey(tn))
                getfisrst(tn);
            HashSet<Character> tvSet = FirstSet.get(tn);
            // 将其非空 first集加入左部
            for (Character tmp : tvSet)
                if (tmp != 'ε')
                    set.add(tmp);
            // 若包含空串 处理下一个符号
            if (tvSet.contains('ε'))
                i++;
                // 否则结束
            else
                break;
            // 到了尾部 即所有符号的first集都包含空串 把空串加入
            if (i == s.length()) {
                set.add('ε');
            }
        }
//        s 是之前收集好的右边的东西
//        System.out.println("");
        System.out.println(String.format("FirstSetX put %s -> %s", s,set));
        FirstSetX.put(s, set);


    }

    /**
     * 生成FOLLOW集
     */
    static void Follow() {
        //此处我多循环了几次，合理的方法应该是看每一个非终结符的follow集是否增加，不增加即可停止循环。
        for (int i = 0; i < 3; i++) {
            for (Character ch : NonTerminatorSet
            ) {
                getFollow(ch);
            }
        }

    }

    static void getFollow(char noTerStart) {
//        产生式
        ArrayList<String> prods = production.get(noTerStart);
        HashSet<Character> setFollow = FollowSet.containsKey(noTerStart) ? FollowSet.get(noTerStart) : new HashSet<Character>();
        //如果是开始符 添加 #
        if (noTerStart == start) {
            setFollow.add('#');
        }
        System.out.println("VtSet 终结符Vt集合");
        System.out.println(TerSet);
        //查找输入的所有产生式，确定c的后跟 终结符
        for (Character noTer : NonTerminatorSet) {
            ArrayList<String> prodsOfNoTer = production.get(noTer);
            for (String prod : prodsOfNoTer)
                for (int i = 0; i < prod.length(); i++){
//                    所有的字符 下一个字符 在 终结符Vt集合 {

//                    产生的后面有个终止
                    if (prod.charAt(i) == noTerStart && i + 1 < prod.length() && TerSet.contains(prod.charAt(i + 1))){
//                            下一个是终止符  产生的
                        char nextCh = prod.charAt(i + 1);
//                            System.out.println("VtSet 终结符Vt集合");
//                            System.out.println(TerSet);

                            char chFollow = prod.charAt(i + 1);
                            System.out.println("chFollow");
                            System.out.println(chFollow);
//                            System.out.println("");
                        System.out.println(String.format("%c -> %s", noTer,prod));

                            System.out.println("前面的是 产生式里如果有他一开始一样的 比如 F->FC F和F一样，并且下面一个是终止的  F->Fc 那么下一个char 会被放进follow集合");
//                            F->Fc
//                            StringUtil.printMarked(prod,Arrays.asList(i,i+1));
//                        也就是follow 里面放的 是 F  这种的 屁股后面跟着的 c 这种 小写的？
//                            StringUtil.printMarked(prod,Arrays.asList(i,i+1),'<','>');
                            StringUtil.printMarked(prod,Arrays.asList(i,i+1),'\'','\'');
//                            setA.add(prod.charAt(i + 1));
                            setFollow.add(nextCh);
                        System.out.println("setFollow");
                        System.out.println(setFollow);
//                            他是针对某个开始的 noter
//                            放进去的是下一个
//                            产生的东西 还能产生？
                        }
                }
//
        }
        System.out.println("========");

        System.out.println("follow 集合");
//        System.out.println("csetA");
        System.out.println(String.format("%c -> %s",noTerStart,setFollow));
//        System.out.println(setA);
        FollowSet.put(noTerStart, setFollow);
        //处理c的每一条产生式
        for (String s : prods) {
            int i = s.length() - 1;
            while (i >= 0) {
                char tn = s.charAt(i);
                //只处理非终结符
                if (NonTerminatorSet.contains(tn)) {
                    // 都按 A->αBβ  形式处理
                    //若β不存在   followA 加入 followB
                    //若β存在，把β的非空first集  加入followB
                    //若β存在  且 first(β)包含空串   followA 加入 followB

                    //若β存在
                    if (s.length() - i - 1 > 0) {
                        String right = s.substring(i + 1);
                        //非空first集 加入 followB
                        HashSet<Character> setF = null;
                        if (right.length() == 1) {
                            if (!FirstSet.containsKey(right.charAt(0)))
                                getfisrst(right.charAt(0));
                            setF = FirstSet.get(right.charAt(0));
                        } else {
                            //先找出右部的first集
                            if (!FirstSetX.containsKey(right))
                                getFirstX(right);
                            setF = FirstSetX.get(right);
                        }
                        HashSet<Character> setX = FollowSet.containsKey(tn) ? FollowSet.get(tn) : new HashSet<Character>();
                        for (Character var : setF)
                            if (var != 'ε')
                                setX.add(var);
                        FollowSet.put(tn, setX);

                        // 若first(β)包含空串   followA 加入 followB
                        if (setF.contains('ε')) {
                            if (tn != noTerStart) {
                                HashSet<Character> setB = FollowSet.containsKey(tn) ? FollowSet.get(tn) : new HashSet<Character>();
                                for (Character var : setFollow)
                                    setB.add(var);
                                FollowSet.put(tn, setB);
                            }
                        }
                    }
                    //若β不存在   followA 加入 followB
                    else {
                        // A和B相同不添加
                        if (tn != noTerStart) {
                            HashSet<Character> setB = FollowSet.containsKey(tn) ? FollowSet.get(tn) : new HashSet<Character>();
                            for (Character var : setFollow)
                                setB.add(var);
                            FollowSet.put(tn, setB);
                        }
                    }
                    i--;
                }
                //如果是终结符往前看  如 A->aaaBCDaaaa  此时β为 CDaaaa
                else i--;
            }
        }
    }

    /**
     * 生成预测分析表
     */
    static void creatTable() {
        Object[] VtArray = TerSet.toArray();
        Object[] VnArray = NonTerminatorSet.toArray();
        // 预测分析表初始化
        table = new String[VnArray.length + 1][VtArray.length + 1];
        table[0][0] = "Vn/Vt";
        //初始化首行首列
        for (int i = 0; i < VtArray.length; i++)
            table[0][i + 1] = (VtArray[i].toString().charAt(0) == 'ε') ? "#" : VtArray[i].toString();
        for (int i = 0; i < VnArray.length; i++)
            table[i + 1][0] = VnArray[i] + "";
        //全部置error
        for (int i = 0; i < VnArray.length; i++)
            for (int j = 0; j < VtArray.length; j++)
                table[i + 1][j + 1] = "error";

        //插入生成式
        for (char A : NonTerminatorSet) {
            ArrayList<String> l = production.get(A);
            for (String s : l) {
                HashSet<Character> set = FirstSetX.get(s);
                for (char a : set)
                    insert(A, a, s);
                if (set.contains('ε')) {
                    HashSet<Character> setFollow = FollowSet.get(A);
                    if (setFollow.contains('#'))
                        insert(A, '#', s);
                    for (char b : setFollow)
                        insert(A, b, s);
                }
            }
        }
    }

    /**
     * 将生成式插入表中
     */
    static void insert(char X, char a, String s) {
        if (a == 'ε') a = '#';
        for (int i = 0; i < NonTerminatorSet.size() + 1; i++) {
            if (table[i][0].charAt(0) == X)
                for (int j = 0; j < TerSet.size() + 1; j++) {
                    if (table[0][j].charAt(0) == a) {
                        table[i][j] = s;
                        return;
                    }
                }
        }
    }

    /**
     * 返回当前栈内容的字符串，与LL(1)无关，为GUI提供字符串
     */
    static String getStack() {
        String str = "";
        for (Character ch : stack
        ) {
            str += ch;
        }
        return str;
    }

    /**
     * 与LL（1）无关，为GUI的表格所需的setpList,提供一行数据
     */
    static void addRowToList(String production, String action) {
        Vector v = new Vector();
        v.add(stepList.size() + 1);
        v.add(getStack());
        v.add(inStr.substring(index));
        v.add(production);
        v.add(action);
        stepList.add(v);
    }

    /**
     * 执行LL1栈分析
     */
    static void processLL1() {
        System.out.println("****************LL分析过程**********");
        System.out.println("               Stack           Input     Action");
        stack.push('#');
        stack.push('E');
        addRowToList("", "");//GUI数据，可不关心
        displayLL();
        char X = stack.peek();
        while (X != '#') {
            char a = inStr.charAt(index);
            if (X == a) {
                action = "match " + stack.peek();
                stack.pop();
                index++;
                addRowToList("", "POP,GETNEXT(I)");//GUI数据，可不关心

            }
//            }else if (VtSet.contains(X))
//                return;
            else if (find(X, a).equals("error")) {
                boolean flag = false;
                if (FirstSet.get(X).contains('ε')) {

                    addRowToList(X + "->ε", "POP");//GUI数据，可不关心
                    action = X + "->ε";
                    stack.pop();
                    flag = true;
                }
                if (!flag) {
                    action = "error";
                    addRowToList("", "ERROR");//GUI数据，可不关心
                    displayLL();
                    return;
                }

            } else if (find(X, a).equals("ε")) {
                stack.pop();
                action = X + "->ε";
                addRowToList(action, "POP");//GUI数据，可不关心
            } else {
                String str = find(X, a);
                if (str != "") {
                    action = X + "->" + str;
                    stack.pop();
                    int len = str.length();
                    String pushStr = "";
                    for (int i = len - 1; i >= 0; i--) {
                        stack.push(str.charAt(i));
                        pushStr += str.charAt(i);
                    }
                    addRowToList(action, "POP,PUSH(" + pushStr + ")");//GUI数据，可不关心
                } else {
                    System.out.println("error at '" + inStr.charAt(index) + " in " + index);
                    return;
                }
            }
            X = stack.peek();
            displayLL();
        }
        System.out.println("analyze LL1 successfully");
        System.out.println("****************LL分析过程**********");
    }

    /**
     * @param X 非终结符
     * @param a 终结符
     * @return 预测分析表中对应内容
     */
    static String find(char X, char a) {
        for (int i = 0; i < NonTerminatorSet.size() + 1; i++) {
            if (table[i][0].charAt(0) == X)
                for (int j = 0; j < TerSet.size() + 1; j++) {
                    if (table[0][j].charAt(0) == a)
                        return table[i][j];
                }
        }
        return "";
    }

    static void displayLL() {
        // 输出 LL1单步处理
        Stack<Character> s = stack;
        System.out.printf("%23s", s);
        System.out.printf("%13s", inStr.substring(index));
        System.out.printf("%10s", action);
        System.out.println();
    }

    /**
     * 打印first.follow集，预测分析表
     */
    static void ouput() {
        System.out.println("*********first集********");
        for (Character c : NonTerminatorSet) {
            HashSet<Character> set = FirstSet.get(c);
            System.out.printf("%10s", c + "  ->   ");
            for (Character var : set)
                System.out.print(var);
            System.out.println();
        }
        System.out.println("**********first集**********");

        System.out.println("**********follow集*********");

        for (Character c : NonTerminatorSet) {
            HashSet<Character> set = FollowSet.get(c);
            System.out.print("Follow " + c + ":");
            for (Character var : set)
                System.out.print(var);
            System.out.println();
        }
        System.out.println("**********follow集**********");

        System.out.println("**********LL1预测分析表********");

        for (int i = 0; i < NonTerminatorSet.size() + 1; i++) {
            for (int j = 0; j < TerSet.size() + 1; j++) {
                System.out.printf("%6s", table[i][j] + " ");
            }
            System.out.println();
        }
        System.out.println("**********LL1预测分析表********");
    }
}

class Gui extends JFrame {
    static JButton btnLL1 = new JButton("LL(1)分析");
    static JTextField input = new JTextField("i+i*i#", 8);
    static JLabel label = new JLabel("输入串:");
    static JLabel first = new JLabel("FIRST:");
    static JLabel follow = new JLabel("FOLLOW:");
    static JLabel tit = new JLabel("---------------      LL(1)单步     -------------");
    static JPanel contentPanel = new JPanel();

    static Vector row = new Vector();
    ;
    static Vector row2 = new Vector();
    static Vector row3 = new Vector();
    static Vector columnNames2 = new Vector();
    static Vector columnNames1 = new Vector();
    static JTable table3;
    static JTable table2;
    static JTable table;

    public static void main(String[] args) {
        new Gui("LL1");
    }

    public Gui(String title) throws HeadlessException {

        super(title);
        setSize(550, 500);
        setResizable(false);

        contentPanel.setLayout(null);
        columnNames1.add("步骤");
        columnNames1.add("分析栈");
        columnNames1.add("剩余输入串");
        columnNames1.add("所用产生式");
        columnNames1.add("动作");
        table = new JTable(row, columnNames1);
        JScrollPane scrollPane1 = new JScrollPane(table);


        columnNames2.add("非终结符");
        columnNames2.add("结果");
        table2 = new JTable(row2, columnNames2);
        JScrollPane scrollPane2 = new JScrollPane(table2);
        table3 = new JTable(row3, columnNames2);
        JScrollPane scrollPane3 = new JScrollPane(table3);
        contentPanel.add(btnLL1);
        contentPanel.add(input);
        contentPanel.add(label);
        contentPanel.add(first);
        contentPanel.add(follow);
        contentPanel.add(scrollPane1);
        contentPanel.add(scrollPane2);
        contentPanel.add(scrollPane3);
        contentPanel.add(tit);

        label.setBounds(5, 5, 110, 30);
        input.setBounds(70, 8, 100, 25);
        btnLL1.setBounds(180, 8, 100, 25);
        first.setBounds(5, 40, 110, 30);
        follow.setBounds(280, 40, 110, 30);
        tit.setBounds(150, 180, 300, 30);
        scrollPane1.setBounds(5, 220, 520, 200);
        scrollPane2.setBounds(5, 70, 250, 100);
        scrollPane3.setBounds(280, 70, 250, 100);
        btnLL1.addActionListener(new Listener());

        this.add(contentPanel);
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    }

    class Listener implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent actionEvent) {

            if (actionEvent.getSource() == btnLL1) {
                String in = input.getText();
                LL1.inStr = in;
                LL1.divideChar();
                LL1.First();
//                LL1.FollowSet
                System.out.println("LL1.FirstSet");
                System.out.println(LL1.FirstSet);
//                System.out.println(Firs);

                for (Character noTer : LL1.NonTerminatorSet
                ) {
                    HashSet<Character> firset = LL1.FirstSet.get(noTer);
//                    System.out.println("fir set");
//                    System.out.println(firset);
                    System.out.println(String.format("no ter to fir set %s -> %s ",noTer,firset) );
                    String token = "";
                    for (Character firSetCh : firset
                    ) {
                        token += firSetCh;
                    }
                    Vector vc = new Vector();
//                    所有的 终结符
                    vc.add(noTer);
                    vc.add(token);
//                    放入了%s -> %s的对应 是为了 界面显示 不关乎逻辑
                    System.out.println("放入了%s -> %s的对应 是为了 界面显示 不关乎逻辑  vector");
                    System.out.println(vc);
                    ((DefaultTableModel) Gui.table2.getModel()).addRow(vc);
                }
                for (Character noTer : LL1.NonTerminatorSet) {
                    ArrayList<String> prods = LL1.production.get(noTer);
                    for (String prod : prods)
                        LL1.getFirstX(prod);
                }
                LL1.Follow();
                for (Character chr : LL1.NonTerminatorSet
                ) {
                    HashSet<Character> firset = LL1.FollowSet.get(chr);
                    String token1 = "";
                    for (Character c : firset
                    ) {
                        token1 += c;
                    }
                    Vector vc1 = new Vector();
                    vc1.add(chr);
                    vc1.add(token1);
                    ((DefaultTableModel) Gui.table3.getModel()).addRow(vc1);
                }
                LL1.creatTable();
                LL1.processLL1();

                for (Vector vc2 : LL1.stepList
                ) {
                    ((DefaultTableModel) Gui.table.getModel()).addRow(vc2);
                }


            }
        }
    }

}
